/*
 * Copyright (C) 2011-2021 Intel Corporation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *   * Neither the name of Intel Corporation nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#pragma once


#ifndef _SE_ARCH_H_
#define _SE_ARCH_H_

#include "inst.h"
#include "se_types.h"
#include "sgx_attributes.h"
#include "sgx_key.h"
#include "sgx_report.h"
#include "sgx_tcrypto.h"

#define SE_PAGE_SIZE 0x1000
#define TCS_SIZE SE_PAGE_SIZE

#pragma pack(push, 1)

#if !defined(__cplusplus) || defined(__INTEL_COMPILER) 
#define _ASSERT_CONCAT(a, b) a##b
#define ASSERT_CONCAT(a, b) _ASSERT_CONCAT(a, b)
#define se_static_assert(e) typedef char ASSERT_CONCAT(assert_line, __LINE__)[(e)?1:-1]
#else
#define se_static_assert(e) static_assert(e,#e)
#endif

se_static_assert(sizeof(sgx_key_request_t) == 512);
se_static_assert(sizeof(sgx_target_info_t) == 512);

//SECS data structure
typedef struct _secs_t
{
    uint64_t                    size;           // (  0) Size of the enclave in bytes
    PADDED_POINTER(void,        base);          // (  8) Base address of enclave
    uint32_t                    ssa_frame_size; // ( 16) size of 1 SSA frame in pages
    sgx_misc_select_t           misc_select;    // ( 20) Which fields defined in SSA.MISC
#define SECS_RESERVED1_LENGTH 24
    uint8_t                     reserved1[SECS_RESERVED1_LENGTH];  // ( 24) reserved
    sgx_attributes_t            attributes;     // ( 48) ATTRIBUTES Flags Field
    sgx_measurement_t           mr_enclave;     // ( 64) Integrity Reg 0 - Enclave measurement
#define SECS_RESERVED2_LENGTH 32
    uint8_t                     reserved2[SECS_RESERVED2_LENGTH];  // ( 96) reserved
    sgx_measurement_t           mr_signer;      // (128) Integrity Reg 1 - Enclave signing key
#define SECS_RESERVED3_LENGTH 32
    uint8_t                     reserved3[SECS_RESERVED3_LENGTH];  // (160) reserved
    sgx_config_id_t             config_id;                        // (192) CONFIGID
    sgx_prod_id_t               isv_prod_id;    // (256) product ID of enclave
    sgx_isv_svn_t               isv_svn;        // (258) Security Version of the Enclave
    sgx_config_svn_t            config_svn;     // (260) CONFIGSVN
#define SECS_RESERVED4_LENGTH 3834
    uint8_t                     reserved4[SECS_RESERVED4_LENGTH];//(262) reserved
} secs_t;

//TCS
// Thread State Definitions
#define SE_STATE_INACTIVE   0            //The TCS is available for a normal EENTER
#define SE_STATE_ACTIVE     1            //A Processor is currently executing in the context of this TCS
// flags definitions
#define DBGOPTIN            1            //used by debugger

typedef struct _tcs_t
{
    uint64_t            state;           // (0)Indicates the current state of the thread.  SE_STATE_xxxx
    uint64_t            flags;           // (8)bit 0: DBGOPTION
    uint64_t            ossa;            // (16)State Save Area
    uint32_t            cssa;            // (24)Current SSA slot
    uint32_t            nssa;            // (28)Number of SSA slots
    uint64_t            oentry;          // (32)Offset in enclave to which control is transferred on EENTER if enclave INACTIVE state
    PADDED_POINTER(void,aep);            // (40)Interrupt return routine. Location reported as exit rip when an asyn exit from the enclave occurs
    uint64_t            ofs_base;        // (48)When added to the base address of the enclave, produces the base address FS segment inside the enclave
    uint64_t            ogs_base;        // (56)When added to the base address of the enclave, produces the base address GS segment inside the enclave
    uint32_t            ofs_limit;       // (64)Size to become the new FS limit in 32-bit mode
    uint32_t            ogs_limit;       // (68)Size to become the new GS limit in 32-bit mode
#define TCS_RESERVED_LENGTH 4024
    uint8_t             reserved[TCS_RESERVED_LENGTH];  // (72)
}tcs_t;

se_static_assert(sizeof(tcs_t) == SE_PAGE_SIZE);

/****************************************************************************
 * Definitions for SSA
 ****************************************************************************/
typedef struct _exit_info_t
{
    uint32_t    vector:8;                // Exception number of exceptions reported inside enclave
    uint32_t    exit_type:3;             // 3: Hardware exceptions, 6: Software exceptions
    uint32_t    reserved:20;
    uint32_t    valid:1;                 // 0: unsupported exceptions, 1: Supported exceptions
} exit_info_t;

#define SE_VECTOR_DE    0
#define SE_VECTOR_DB    1
#define SE_VECTOR_BP    3
#define SE_VECTOR_BR    5
#define SE_VECTOR_UD    6
#define SE_VECTOR_MF    16
#define SE_VECTOR_AC    17
#define SE_VECTOR_XM    19

typedef struct _ssa_gpr_t
{
    REGISTER(   ax);                    // (0)
    REGISTER(   cx);                    // (8)
    REGISTER(   dx);                    // (16)
    REGISTER(   bx);                    // (24)
    REGISTER(   sp);                    // (32)
    REGISTER(   bp);                    // (40)
    REGISTER(   si);                    // (48)
    REGISTER(   di);                    // (56)
    uint64_t    r8;                     // (64)
    uint64_t    r9;                     // (72)
    uint64_t    r10;                    // (80)
    uint64_t    r11;                    // (88)
    uint64_t    r12;                    // (96)
    uint64_t    r13;                    // (104)
    uint64_t    r14;                    // (112)
    uint64_t    r15;                    // (120)
    REGISTER(flags);                    // (128)
    REGISTER(   ip);                    // (136)
    REGISTER( sp_u);                    // (144) untrusted stack pointer. saved by EENTER
    REGISTER( bp_u);                    // (152) untrusted frame pointer. saved by EENTER
    exit_info_t exit_info;              // (160) contain information for exits
    uint32_t    reserved;               // (164) padding to multiple of 8 bytes
    uint64_t    fs;                     // (168) FS register
    uint64_t    gs;                     // (176) GS register
} ssa_gpr_t;

typedef uint64_t si_flags_t;

#define SI_FLAG_NONE                0x0
#define SI_FLAG_R                   0x1             // Read Access
#define SI_FLAG_W                   0x2             // Write Access
#define SI_FLAG_X                   0x4             // Execute Access
#define SI_FLAG_PENDING             0x8             // Page is Pending
#define SI_FLAG_MODIFIED            0x10            // Page is Modified

#define SI_FLAG_PR                  0x20            // Page Permission is Reduced
#define SI_FLAG_PT_LOW_BIT          0x8                             // PT low bit
#define SI_FLAG_PT_MASK             (0xFF<<SI_FLAG_PT_LOW_BIT)      // Page Type Mask [15:8]
#define SI_FLAG_SECS                (0x00<<SI_FLAG_PT_LOW_BIT)      // SECS
#define SI_FLAG_TCS                 (0x01<<SI_FLAG_PT_LOW_BIT)      // TCS
#define SI_FLAG_REG                 (0x02<<SI_FLAG_PT_LOW_BIT)      // Regular Page
#define SI_FLAG_TRIM                (0x04<<SI_FLAG_PT_LOW_BIT)      // Trimmed Page

#define SI_FLAGS_EXTERNAL           (SI_FLAG_PT_MASK | SI_FLAG_R | SI_FLAG_W | SI_FLAG_X)   // Flags visible/usable by instructions
#define SI_FLAGS_R                  (SI_FLAG_R|SI_FLAG_REG)
#define SI_FLAGS_RW                 (SI_FLAG_R|SI_FLAG_W|SI_FLAG_REG)
#define SI_FLAGS_RX                 (SI_FLAG_R|SI_FLAG_X|SI_FLAG_REG)
#define SI_FLAGS_TCS                (SI_FLAG_TCS)
#define SI_FLAGS_SECS               (SI_FLAG_SECS)
#define SI_FLAGS_TRIM               (SI_FLAG_TRIM)
#define SI_MASK_TCS                 (SI_FLAG_PT_MASK)
#define SI_MASK_MEM_ATTRIBUTE       (0x7)


typedef struct _sec_info_t
{
   si_flags_t        flags;
   uint64_t          reserved[7];
} sec_info_t;

typedef struct _page_info_t
{
    PADDED_POINTER(void,        lin_addr);      // Enclave linear address
    PADDED_POINTER(void,        src_page);      // Linear address of the page where contents are located
    PADDED_POINTER(sec_info_t,  sec_info);      // Linear address of the SEC_INFO structure for the page
    PADDED_POINTER(void,        secs);          // Linear address of EPC slot that contains SECS for this enclave
} page_info_t;

/****************************************************************************
* Definitions for enclave signature
****************************************************************************/
#define SE_KEY_SIZE         384         // in bytes
#define SE_EXPONENT_SIZE    4           // RSA public key exponent size in bytes

typedef struct _css_header_t {          // 128 bytes
    uint32_t header_type;               // (0)  Module type (Must be 6)
    uint32_t header_len;                // (4)  Header length including crypto fields (dwords) (Must be 00E1h)
    uint32_t header_version;            // (8)  Struct version (Must be 00010000h)
    uint32_t type;                      // (12) bit 31: 0 = prod, 1 = debug; Bit 30-0: Must be zero
    uint32_t module_vendor;             // (16) Intel=0x8086, ISV=0x0000
    uint32_t date;                      // (20) build date as yyyymmdd
    uint32_t size;                      // (24) Size of the entire module (dwords) (Must be 0101h)
    uint32_t key_size;                  // (28) RSA public key modulus size (dwords) (Must be 0060h in SE1.5)
    uint32_t modulus_size;              // (32) RSA public key modulus size (dwords) (Must be 0060h in SE1.5)
    uint32_t exponent_size;             // (36) RSA public key exponent size (dword) (Must be 0001h in SE1.5)
    uint32_t hw_version;                // (40) For License Enclaves: HWVERSION != 0. Others, HWVERSION = 0
    uint8_t  reserved[84];              // (44) Must be 0
} css_header_t;
se_static_assert(sizeof(css_header_t) == 128);

typedef struct _css_key_t {             // 772 bytes
    uint8_t modulus[SE_KEY_SIZE];       // (128) Module Public Key (keylength=3072 bits)
    uint8_t exponent[SE_EXPONENT_SIZE]; // (512) RSA Exponent = 3
    uint8_t signature[SE_KEY_SIZE];     // (516) Signature over Header and Body
} css_key_t;
se_static_assert(sizeof(css_key_t) == 772);

typedef struct _css_body_t {            // 128 bytes
    sgx_misc_select_t   misc_select;    // (900) The MISCSELECT that must be set
    sgx_misc_select_t   misc_mask;      // (904) Mask of MISCSELECT to enforce
    uint8_t              reserved[4];    // (908) Reserved. Must be 0.
    sgx_isvfamily_id_t   isv_family_id;  // (912) ISV assigned Family ID
    sgx_attributes_t    attributes;     // (928) Enclave Attributes that must be set
    sgx_attributes_t    attribute_mask; // (944) Mask of Attributes to Enforce
    sgx_measurement_t   enclave_hash;   // (960) MRENCLAVE - (32 bytes)
    uint8_t              reserved2[16];  // (992) Must be 0
    sgx_isvext_prod_id_t isvext_prod_id; // (1008) ISV assigned Extended Product ID
    uint16_t            isv_prod_id;    // (1024) ISV assigned Product ID
    uint16_t            isv_svn;        // (1026) ISV assigned SVN
} css_body_t;
se_static_assert(sizeof(css_body_t) == 128);

typedef struct _css_buffer_t {          // 780 bytes
    uint8_t  reserved[12];              // (1028) Must be 0
    uint8_t  q1[SE_KEY_SIZE];           // (1040) Q1 value for RSA Signature Verification
    uint8_t  q2[SE_KEY_SIZE];           // (1424) Q2 value for RSA Signature Verification
} css_buffer_t;
se_static_assert(sizeof(css_buffer_t) == 780);

typedef struct _enclave_css_t {         // 1808 bytes
    css_header_t    header;             // (0)
    css_key_t       key;                // (128)
    css_body_t      body;               // (900)
    css_buffer_t    buffer;             // (1028)
} enclave_css_t;

se_static_assert(sizeof(enclave_css_t) == 1808);

/****************************************************************************
* Definitions for launch token
****************************************************************************/
typedef struct _launch_body_t
{
   uint32_t              valid;            // (  0) 0 = Invalid, 1 = Valid
   uint32_t              reserved1[11];    // (  4) must be zero
   sgx_attributes_t      attributes;       // ( 48) ATTRIBUTES of Enclave
   sgx_measurement_t     mr_enclave;       // ( 64) MRENCLAVE of Enclave
   uint8_t               reserved2[32];    // ( 96)
   sgx_measurement_t     mr_signer;        // (128) MRSIGNER of Enclave
   uint8_t               reserved3[32];    // (160)
} launch_body_t;
se_static_assert(sizeof(launch_body_t) == 192);

typedef struct _launch_t {
  launch_body_t         body;
  sgx_cpu_svn_t          cpu_svn_le;       // (192) Launch Enclave's CPUSVN
  uint16_t               isv_prod_id_le;   // (208) Launch Enclave's ISVPRODID
  uint16_t               isv_svn_le;       // (210) Launch Enclave's ISVSVN
  uint8_t                reserved2[24];    // (212) Must be 0
  sgx_misc_select_t      masked_misc_select_le; // (236)
  sgx_attributes_t       attributes_le;    // (240) ATTRIBUTES of Launch Enclave
  sgx_key_id_t           key_id;           // (256) Value for key wear-out protection
  sgx_mac_t              mac;              // (288) CMAC using Launch token Key
} token_t;
se_static_assert(sizeof(token_t) == 304);

typedef struct _wl_cert_t                           // All fields except the mr_signer_list fields, are big-endian integer format
{
    uint16_t                version;                // ( 0) White List Cert format version. For 2015, only valid version is 1
    uint16_t                cert_type;              // ( 2) White List Cert Type. For Enclave Signing Key White List Cert, must be 1
    uint16_t                provider_id;            // ( 4) Enclave Signing Key White List Provider ID to identify the key used to sign this Enclave signing Key White List Certificate. For 2015, only one White List Provider is approved: WLProviderID-ISecG = 0
    uint16_t                le_prod_id;             // ( 6) Launch Enclave ProdID the White List Cert applies to.  Launch Enclave for different OS might be assigned with different ProdID. Attackers can't simply use a White List for one OS in another OS. Windows LE-ProdID = 0x00; Android LE-ProdID = 0x10; Linux LE-ProdID = 0x20
    uint32_t                wl_version;             // ( 8) Version of the Enclave Signing Key White List. For a specific LE-ProdID, should increase on every WL Cert signing request
    uint32_t                entry_number;           // (12) Number of MRSIGNER entries in the Cert. If the White List Certificate allows enclave signed by any key to launch, the White List Cert must only contain one all-0 MRSIGNER entry.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning ( disable:4200 )
#endif
    sgx_measurement_t       mr_signer_list[];       // (16) White Listed Enclave Signing Key entry 0 - SHA256 Hash of the little-endian format RSA-3072 Enclave Signing Key modulus. If the White List Cert allows enclave signed by any key to launch, this field must be all 0s
#ifdef _MSC_VER
#pragma warning(pop)
#endif
}wl_cert_t;
typedef struct _wl_provider_cert_t                  // All fields are big endian
{
    uint16_t                version;                // ( 0) White List Cert format version. For 2015, only valid version is 1
    uint16_t                cert_type;              // ( 2) White List Cert Type, For Enclave Signing Key White List Signer Cert, must be 0
    uint16_t                provider_id;            // ( 4) Enclave Signing Key White List Signer ID assigned by the White List Root CA. For 2015, only one White List Provider is approved: WLProviderID-ISecG = 0
    uint16_t                root_id;                // ( 6) Identify the White List Root CA key used to sign the Cert. For 2015, only one WLRootID is valid: WLRootID-iKGF-Key-0 = 0
    sgx_ec256_public_t      pub_key;                // ( 8) ECDSA public key of the Enclave Signing Key White List Provider identified by WLProviderID
    sgx_ec256_signature_t   signature;              // (72) ECDSA Signature by WL Root CA identified by WLRootID
}wl_provider_cert_t;
se_static_assert(sizeof(wl_provider_cert_t) == 136);
typedef struct _wl_cert_chain_t
{
    wl_provider_cert_t      wl_provider_cert;
    wl_cert_t               wl_cert;
}wl_cert_chain_t;
#pragma pack(pop)



typedef enum sgx_einit_error_codes_t
{
    SGX_NO_ERROR                    = 0,
    SGX_INVALID_SIG_STRUCT          = 1,
    SGX_INVALID_ATTRIBUTE           = 2,
    SGX_INVALID_MEASUREMENT         = 4,
    SGX_INVALID_SIGNATURE           = 8,
    SGX_INVALID_EINIT_TOKEN         = 16,
    SGX_INVALID_CPUSVN              = 32,
    SGX_UNMASKED_EVENT              = 128
} sgx_einit_error_codes_t;

/* DeviceIoControl return values */
#define SGX_POWER_LOST_ENCLAVE    0x40000000
#define SGX_LE_ROLLBACK           0x40000001
#define SGX_INVALID_PRIVILEGE     0x40000002
#define SGX_UNEXPECTED_ERROR      0x40000003

#endif//_SE_ARCH_H_

